/* Exercise 5.1 LCD utilities */ /* Created David Miles April 2006 */ /* Updated Ben Rowland Febuary 2014 */ //Connects 2 line LCD panel using Hitachi 44780 controller //Assigments as follows: //PORTB:0 -----> LCD bit 4 //PORTB:1 -----> LCD bit 5 //PORTB:2 -----> LCD bit 6 //PORTB:3 -----> LCD bit 7 //PORTB:4 -----> LCD RS //PORTB:5 -----> LCD E #include // CONFIG1 #pragma config FOSC = HS // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable (All VCAP pin functionality is disabled) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) #define _XTAL_FREQ 19660800 // Defines the hardware crystal frequency allowing the delay function to work correctly #define RSMASK 0x10 // Masks for control bits #define EBIT 0x05 #define PUTCH_DELAY 250 // Defined values for delays tested up to 20Mhz PIC standard write delay #define CLEAR_DELAY 5000 // Clear and cursor home take longer special delay for them #define POWER_UP_DELAY 10000 // Power up delay to let the LCD settle #define BIT_DELAY 2 // Bit delay to let the ports settle //LCD function prototypes char lcd_start (void); char lcd_clear (void); char lcd_print_ch (char ch); char lcd_print (const char * message); char lcd_cursor (char x, char y); void lcd_delay ( int size ) { int i ; for ( i = 0 ; i < size ; i++ ) ; } //Swaps the high and low nibbles in a byte unsigned char lcd_swap_nibble (unsigned char data) { unsigned char swap_data; swap_data = (data & 0xF0) >> 4; swap_data |= (data & 0x0F) << 4; return (swap_data); } //Sends a byte out to the LCD the byte is given by in, the mask is used to allow the state of RS to be set as well void lcd_raw_send ( unsigned char in, unsigned char mask ) { unsigned char pb ; //Swap the nibbles in the input puts high nibble at the bottom of the byte in = lcd_swap_nibble(in); pb = (in & 0x0f ) | mask; //OR in the mask pb = pb | ( PORTB & 0xc0); //OR in the other bits PORTB LATB = pb; //send the data don't disturb the other bits in PORTB lcd_delay ( BIT_DELAY ); //let the bits settle LATB = pb | 1 << EBIT; //now clock the bit out by raising and lowering E lcd_delay ( BIT_DELAY ); //let the bits settle LATB = pb; //Swap the nibbles in the input puts high nibble at the bottom of the byte in = lcd_swap_nibble(in); pb = (in & 0x0f ) | mask; //OR in the mask pb = pb | ( PORTB & 0xc0); //OR in the other bits PORTB LATB = pb; //send the data don't disturb the other bits in PORTB lcd_delay ( BIT_DELAY ); //let the bits settle LATB = pb | 1 << EBIT; //now clock the bit out by raising and lowering E lcd_delay ( BIT_DELAY ); //let the bits settle LATB = pb; lcd_delay (PUTCH_DELAY) ; //do the delay here } // puts a character at the cursor position char lcd_print_ch ( unsigned char in ) { lcd_raw_send ( in, RSMASK ) ; //use raw send with RS set return 1 ; } //sends a command to the LCD void lcd_command ( unsigned char in ) { lcd_raw_send ( in, 0 ) ; } //Clear the display and home the cursor char lcd_clear ( void ) { lcd_command ( 0x01 ) ; lcd_delay (CLEAR_DELAY) ; //do extra delay here lcd_command ( 0x02 ) ; lcd_delay (CLEAR_DELAY) ; //do extra delay here return 1 ; } //position the cursor char lcd_cursor (unsigned char x, unsigned char y) { if ( y==0 ) { y=0x80; //position for line 0 } else { y=0xc0; //position for line 1 } lcd_command (y + x); return 1; } const unsigned char lcd_init [5] = { /* LCD initialise */ 0x33, /* Set for 4 bit operation */ 0x32, /* Set for 2 line LCD */ 0x2c, /* Select move after write */ 0x06, /* disp. on cursor off blink off */ 0x0c } ; char lcd_start (void) { unsigned char i; TRISB = (TRISB & 0xc0); //set bits of PORTB for output change for different hardware clear bottom five bits for LCD don't change any other bits lcd_delay ( POWER_UP_DELAY ); //give the LCD time to settle from power up for ( i=0 ; i < 5 ; i++ ) //loop through init data { lcd_command(lcd_init[i]); //send out init data } lcd_clear(); //clear LCD return 1 ; } //lcd_print accepts a pointer parameter which points at the string to be printed */ char lcd_print ( const unsigned char * mess ) { unsigned char i = 0 ; while (mess [i] != 0) //treat the pointer as an array and send bytes until we find an element with 0 in it { lcd_print_ch (mess[i]); //Print character in current position of string array i++ ; //Move to next } return 1 ; } const unsigned char hello [6] = { 'h','e','l','l','o',0x00 } ; int main (void) { ANSELB = 0x00; //Put PORTB into Digital mode, defaults to analogue OPTION_REG = 0xC0; while (1) //Loop forever { lcd_start (); lcd_cursor ( 5, 0 ); lcd_print ( hello ); lcd_cursor ( 0, 0 ); lcd_print_ch ( 'x' ); lcd_cursor ( 15, 0 ); lcd_print_ch ( 'x' ); lcd_cursor ( 0, 1 ); lcd_print_ch ( 'x' ); lcd_cursor ( 15, 1 ); lcd_print_ch ( 'x' ); } return 0; }